/**
 * @FileName: ExceptionProxy.java
 * @Package: com.ziroom.zmc.services.knowledge.exception
 * @author youshipeng
 * @created 2016/11/14 16:35
 * <p>
 * Copyright 2016 ziroom
 */
package top.swimmer.tools.exception;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * <p></p>
 *
 * <PRE>
 * <BR>	修改记录
 * <BR>-----------------------------------------------
 * <BR>	修改日期			修改人			修改内容
 * </PRE>
 *
 * @author youshipeng
 * @since 1.0
 * @version 1.0
 */
public class ExceptionProxy implements InvocationHandler {

    @SuppressWarnings("unchecked")
    public static <T> T newProxyInstance(Class<T> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, new ExceptionProxy());
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ExceptionDef exceptionDef = method.getAnnotation(ExceptionDef.class);
        if (exceptionDef == null) {
            return new BaseException(80000000, "");
        }

        String message = exceptionDef.message();
        int code = exceptionDef.code();
        Throwable throwable = null;
        if (args != null && args.length != 0) {
            message = formatMessage(message, args);
            if (args[0] instanceof Throwable) {
                throwable = (Throwable) args[0];
            }
        }

        Class throwableClass = method.getReturnType();
        Constructor constructor = throwableClass.getConstructor(int.class, String.class);

        if (throwable != null) {
            constructor = throwableClass.getConstructor(int.class, String.class, Throwable.class);
            return constructor.newInstance(code, message, throwable);
        }
        return constructor.newInstance(code, message);
    }

    private String formatMessage(String pattern, Object[] args) {
        if (pattern == null) {
            return null;
        }

        int index = 0;
        for (Object arg : args) {
            if (!(arg instanceof Throwable)) {
                String argStr = "{null}";

                if (arg != null) {
                    argStr = arg.toString();
                }

                pattern = pattern.replace("{" + index + "}", argStr);
                index++;
            }
        }

        return pattern;
    }

}